

#include "mainwindow.h"
#include "CNwidget.h"
#include "spectrumapp/mainwidget.h"
#include <QLoggingCategory>
#include <QDir>

/*

#include "string"
#include "Hanz2Piny.h"
#include "hanzi2phoneid.h"
#include <iostream>
#include <fstream>


#include "stdio.h"
#include <sys/time.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include "stdlib.h"
#include <ctime>
#include "extract_feat.h"
#include "stdint.h"

*/


#include "tts.h"
#include "asr.h"


using namespace std;


/*
WorkerThread::WorkerThread():QThread()
{
}
void WorkerThread::setrun(MainWindow*pwd,QString& qsfile)
{
    m_pwd=pwd;
    m_qsfile=qsfile;
}
void WorkerThread::run()
{

    struct stat st;

    if(-1 == stat(m_qsfile.toLatin1(), &st))
    {
        return ;
    }
    FILE *fp = fopen(m_qsfile.toLatin1(), "rb");
    if(!fp)
    {
        printf("Fail to open wav file:in.wav!\n");
        return ;
    }

    fseek(fp, 44, SEEK_SET);

    float wavDur = (float)((st.st_size-44)/32000.0);

    int16_t * wavBuf = (int16_t *)malloc(st.st_size-44);
    fread(wavBuf,st.st_size-44, 1, fp);
    fclose(fp);

    struct timeval start, end;
    float timeuse,t;

    //omp_set_num_threads(6);

    gettimeofday( &start, NULL );

    void * asrData = asrInit("./model/am.model","./model/char.txt","./model/lm.model", false);

    gettimeofday( &end, NULL );
    timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
    std::cout<<"Model loading time costs:"<<std::setprecision(6)<<timeuse/1000000<<'s'<<"\n";

    gettimeofday( &start, NULL );

    std::string asrResult =  asrRun_without_vad(asrData, wavBuf, (((st.st_size)-44)/2));

    gettimeofday( &end, NULL );
m_pwd->ui.asrTextEdit->setPlainText(m_pwd->ui.asrTextEdit->toPlainText()+asrResult.c_str());
    printf("Asr Result: %s\n",asrResult.c_str());
m_pwd->m_w->m_bfinish=true;
    timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
    std::cout<<"Wav duration: "<<std::setprecision(6)<<wavDur<< "s, Asr Decoding time costs: "<<std::setprecision(6)<<timeuse/1000000<<"s, RTF: "<<std::setprecision(6)<<(timeuse/1000000)/wavDur<<"\n";
}
*/


void MainWindow::ttsa()
{// ./test.txt
/*  唤醒
    const Hanz2Piny hanz2piny;


    if (hanz2piny.isStartWithBom(line))
    {
        line = std::string(line.cbegin() + 3, line.cend());
    }
*/


    QString qstrline=ui.plainTextEdit->toPlainText();
    std::string line;
    line=qstrline.toStdString();
    QString qmf="./models/"+ui.ttsmodel->currentText();

    m_tts->setmodel(qmf.toLocal8Bit());
    m_tts->ttsa(line,ui.TTSlineEdit->text().toLatin1());
    /*
    QString qstrline=ui.plainTextEdit->toPlainText();
    std::string line;
    line=qstrline.toStdString();
    QString qmf="./models/"+ui.ttsmodel->currentText();

    float * dataW = NULL;
    //int32_t modelSize = ttsLoadModel("./models/single_speaker_small.bin",&dataW);
    int32_t modelSize = ttsLoadModel(qmf.toLocal8Bit(),&dataW);

    SynthesizerTrn * synthesizer = new SynthesizerTrn(dataW);

    {
        int32_t retLen = 0;
        int16_t * wavData = synthesizer->infer(line,0, 1.1,retLen);

        char * dataForFile = new char[retLen*sizeof(int16_t)+44];
        convertAudioToWavBuf1(dataForFile, (char *)wavData, retLen*sizeof(int16_t));

        FILE * fpOut = fopen(ui.TTSlineEdit->text().toLatin1(),"wb");
        fwrite(dataForFile, retLen*sizeof(int16_t)+44, 1, fpOut);
        fclose(fpOut);
        tts_free_data(wavData);
    }

    tts_free_data(dataW);
*/
}

void MainWindow::asra()
{
/*
    struct stat st;

    if(-1 == stat(ui.ASRlineEdit->text().toLatin1(), &st))
    {
        return ;
    }
    FILE *fp = fopen(ui.ASRlineEdit->text().toLatin1(), "rb");
    if(!fp)
    {
        printf("Fail to open wav file:in.wav!\n");
        return ;
    }

    fseek(fp, 44, SEEK_SET);

    float wavDur = (float)((st.st_size-44)/32000.0);

    int16_t * wavBuf = (int16_t *)malloc(st.st_size-44);
    fread(wavBuf,st.st_size-44, 1, fp);
    fclose(fp);

    struct timeval start, end;
    float timeuse,t;



    gettimeofday( &start, NULL );
if(0)
    std::string asrResult =  asrRun_without_vad(wavBuf, (((st.st_size)-44)/2));

    std::string asrResult;

    std::vector<std::string> astr = asrRun_with_vad( wavBuf, (((st.st_size)-44)/2));

    for (int ia=0; ia<astr.size(); ia++)
    {
        if(ia>0)
            asrResult=asrResult+","+astr[ia];
        else
            asrResult=astr[ia];
    }
    gettimeofday( &end, NULL );

ui.asrTextEdit->setPlainText(ui.asrTextEdit->toPlainText()+asrResult.c_str());
    printf("Asr Result: %s\n",asrResult.c_str());

    timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
    std::cout<<"Wav duration: "<<std::setprecision(6)<<wavDur<< "s, Asr Decoding time costs: "<<std::setprecision(6)<<timeuse/1000000<<"s, RTF: "<<std::setprecision(6)<<(timeuse/1000000)/wavDur<<"\n";


*/

    m_asr->asra(ui.ASRlineEdit->text().toLatin1());

    ui.asrTextEdit->setPlainText(ui.asrTextEdit->toPlainText()+m_asr->getresult().c_str());

}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
    m_speech(nullptr)
{
    ui.setupUi(this);
    QLoggingCategory::setFilterRules(QStringLiteral("qt.speech.tts=true \n qt.speech.tts.*=true"));

    m_w=new MainWidget();
    m_w->show();

    CNtable = new CNWidget;
    CNtable->setMinimumHeight(46);
    CNtable->setMaximumHeight(46);
    //QApplication::clipboard()->setText(CNtable->getstring());

    ui.verticalLayout->addWidget(CNtable);
    // Populate engine selection list
    ui.engine->addItem("Default", QString("default"));
    const auto engines = QTextToSpeech::availableEngines();
    for (const QString &engine : engines)
        ui.engine->addItem(engine, engine);
    ui.engine->setCurrentIndex(0);
    engineSelected(0);

     QDir secdir("models");
     QStringList mfiles;
     foreach (const QFileInfo &adirznname,secdir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot ))
     {
        ui.ttsmodel->addItem(adirznname.fileName(), adirznname.fileName());
    }
        ui.ttsmodel->setCurrentIndex(ui.ttsmodel->count()-1);

    connect(ui.TTSButton, &QPushButton::clicked, this, &MainWindow::runTTS);
    connect(ui.ASRButton, &QPushButton::clicked, this, &MainWindow::runASR);
    connect(ui.testButton, &QPushButton::clicked, this, &MainWindow::Test);


    connect(ui.speakButton, &QPushButton::clicked, this, &MainWindow::speak);
    connect(ui.pitch, &QSlider::valueChanged, this, &MainWindow::setPitch);
    connect(ui.rate, &QSlider::valueChanged, this, &MainWindow::setRate);
    connect(ui.volume, &QSlider::valueChanged, this, &MainWindow::setVolume);
    connect(ui.engine, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::engineSelected);


    connect(m_w, &MainWidget::asrsignals,this, &MainWindow::ASRFile);

    QString qmf="./models/"+ui.ttsmodel->currentText();
    m_asr = new ASR();
    m_tts = new TTS(qmf.toLocal8Bit());
}
void MainWindow::runTTS()
{
    ui.TTSButton->setEnabled(false);
    ttsa();
    m_w->loadfile("out.wav");
    m_w->play();
    ui.TTSButton->setEnabled(true);
    return;
}

void MainWindow::ASRFile(QString &qsfile)
{
    ui.ASRlineEdit->setText(qsfile);
   // ui.ASRButton->setEnabled(false);
//    m_thread.setrun(this,qsfile);
//    m_thread.start();
    //asra();
   // ui.ASRButton->setEnabled(true);
}
void MainWindow::runASR()
{
    ui.ASRButton->setEnabled(false);
    asra();
    ui.ASRButton->setEnabled(true);
}
void MainWindow::Test()
{
    //m_w->savewav();
    ui.testButton->setEnabled(false);
    m_w->recording();
    ui.testButton->setEnabled(true);
}

void MainWindow::speak()
{
    m_speech->say(ui.plainTextEdit->toPlainText());
}
void MainWindow::stop()
{
    m_speech->stop();
}

void MainWindow::setRate(int rate)
{
    m_speech->setRate(rate / 10.0);
}

void MainWindow::setPitch(int pitch)
{
    m_speech->setPitch(pitch / 10.0);
}

void MainWindow::setVolume(int volume)
{
    m_speech->setVolume(volume / 100.0);
}

void MainWindow::stateChanged(QTextToSpeech::State state)
{
    if (state == QTextToSpeech::Speaking) {
        ui.statusbar->showMessage("Speech started...");
    } else if (state == QTextToSpeech::Ready)
        ui.statusbar->showMessage("Speech stopped...", 2000);
    else if (state == QTextToSpeech::Paused)
        ui.statusbar->showMessage("Speech paused...");
    else
        ui.statusbar->showMessage("Speech error!");

    ui.pauseButton->setEnabled(state == QTextToSpeech::Speaking);
    ui.resumeButton->setEnabled(state == QTextToSpeech::Paused);
    ui.stopButton->setEnabled(state == QTextToSpeech::Speaking || state == QTextToSpeech::Paused);
}

void MainWindow::engineSelected(int index)
{
    QString engineName = ui.engine->itemData(index).toString();
    delete m_speech;
    if (engineName == "default")
        m_speech = new QTextToSpeech(this);
    else
        m_speech = new QTextToSpeech(engineName, this);
    disconnect(ui.language, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::languageSelected);
    ui.language->clear();
    // Populate the languages combobox before connecting its signal.
    const QVector<QLocale> locales = m_speech->availableLocales();
    QLocale current = m_speech->locale();
    for (const QLocale &locale : locales) {
        QString name(QString("%1 (%2)")
                     .arg(QLocale::languageToString(locale.language()))
                     .arg(QLocale::countryToString(locale.country())));
        QVariant localeVariant(locale);
        ui.language->addItem(name, localeVariant);
        if (locale.name() == current.name())
            current = locale;
    }
    setRate(ui.rate->value());
    setPitch(ui.pitch->value());
    setVolume(ui.volume->value());
    connect(ui.stopButton, &QPushButton::clicked, m_speech, &QTextToSpeech::stop);
    connect(ui.pauseButton, &QPushButton::clicked, m_speech, &QTextToSpeech::pause);
    connect(ui.resumeButton, &QPushButton::clicked, m_speech, &QTextToSpeech::resume);

    connect(m_speech, &QTextToSpeech::stateChanged, this, &MainWindow::stateChanged);
    connect(m_speech, &QTextToSpeech::localeChanged, this, &MainWindow::localeChanged);

    connect(ui.language, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::languageSelected);
    localeChanged(current);
}

void MainWindow::languageSelected(int language)
{
    QLocale locale = ui.language->itemData(language).toLocale();
    m_speech->setLocale(locale);
}

void MainWindow::voiceSelected(int index)
{
    m_speech->setVoice(m_voices.at(index));
}

void MainWindow::localeChanged(const QLocale &locale)
{
    QVariant localeVariant(locale);
    ui.language->setCurrentIndex(ui.language->findData(localeVariant));

    disconnect(ui.voice, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::voiceSelected);
    ui.voice->clear();

    m_voices = m_speech->availableVoices();
    QVoice currentVoice = m_speech->voice();
    for (const QVoice &voice : qAsConst(m_voices)) {
        ui.voice->addItem(QString("%1 - %2 - %3").arg(voice.name())
                          .arg(QVoice::genderName(voice.gender()))
                          .arg(QVoice::ageName(voice.age())));
        if (voice.name() == currentVoice.name())
            ui.voice->setCurrentIndex(ui.voice->count() - 1);
    }
    connect(ui.voice, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::voiceSelected);
}
